package com.jy.api.controller.admin;

import com.jy.api.config.WebSocketUrlUtils;
import com.jy.api.controller.MarsCall.LeaseProductOrderParams;
import com.jy.api.controller.MarsCall.LeaseSumAmountResult;
import com.jy.api.dao.*;
import com.jy.api.domain.*;
import com.jy.api.enums.OrderItemMakeType;
import com.jy.api.service.OrderService;
import com.jy.api.service.ProductTypeService;
import com.jy.api.signUpReq.AddMatchOrderItemParams;
import com.jy.api.util.DateAndTimeUtil;
import com.jy.api.util.OkHttpUtils;
import com.jy.api.util.RedisSyncLocker;
import com.jy.api.util.TimeUtils;
import com.jy.api.vo.admin.AdminOrderVo;
import com.jy.api.vo.pos.order.OrderVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by lihu on 2017/10/30.
 */

@Slf4j
@RestController
@RequestMapping(value = "v1/admin", produces = "application/json;charset=utf-8")
public class AdminOrderController {


    @Autowired
    OrderDao orderDao;


    @Autowired
    OrderService orderService;

    @Autowired
    StoreDao storeDao;


    @Autowired
    OrderItemDao orderItemDao;

    @Autowired
    ProductTypeService productTypeService;
    @Autowired
    private RedisSyncLocker redisSyncLocker;
    @Autowired
    private MakeOrderItemDao makeOrderItemDao;
    @Autowired
    private WebSocketUrlUtils urlUtils;
    @Autowired
    private MakeOrderDao makeOrderDao;
    @Autowired
    private LeaseProductOrderDao leaseProductOrderDao;
    @Autowired
    private WorkShiftDao workShiftDao;
    private JdbcTemplate jdbc;
    @Autowired
    public void setJdbc(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }


    @PostMapping("/lease/order/list")
    public ResponseEntity orderList(@RequestBody LeaseProductOrderParams params){
        try {
            LeaseSumAmountResult result = new LeaseSumAmountResult();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            List<Object[]> orderTotal = leaseProductOrderDao.sumByStoreId(params.getStoreId(), sdf.parse(params.getBeginTime()), sdf.parse(params.getEndTime()));
            // SUM(get_amount),SUM(refund_amount),SUM(pay_amount)
            for (Object[] objects : orderTotal) {
                result.setGetAmount(objects[0].toString());
                result.setRefundAmount(objects[1].toString());
                result.setTotalAmount(objects[2].toString());
            }
            Specification<LeaseProductOrder> netSpec = (root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(criteriaBuilder.equal(root.get("storeId"), params.getStoreId()));
                if (StringUtils.isNotBlank(params.getMobile())) {
                    predicates.add(criteriaBuilder.like(root.get("mobile"), params.getMobile()));
                }
                if (!StringUtils.isBlank(params.getBeginTime())) {
                    try {
                        predicates.add(criteriaBuilder.greaterThan(root.get("refundTime"), sdf.parse(params.getBeginTime())));
                        predicates.add(criteriaBuilder.lessThan(root.get("refundTime"), sdf.parse(params.getEndTime())));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                final CriteriaBuilder.In<Object> sectionId = criteriaBuilder.in(root.get("status"));
                List<OrderStatus> orderStatuses = new ArrayList<>();
                orderStatuses.add(OrderStatus.FINISHED);
                orderStatuses.add(OrderStatus.REFUNDED);
                for (OrderStatus section : orderStatuses) {
                    sectionId.value(section);
                }
                predicates.add(sectionId);
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            };
            List<Sort.Order> netOrders = new ArrayList<>();
            netOrders.add(new Sort.Order(Sort.Direction.DESC, "refundTime"));
            netOrders.add(new Sort.Order(Sort.Direction.DESC, "id"));
            //查询包含系统网费的
            Page<LeaseProductOrder> orders = leaseProductOrderDao.findAll(netSpec, new PageRequest(params.getPage(), params.getSize(), new Sort(netOrders)));
            Map map = new HashMap();
            map.put("data", orders.getContent());
            map.put("totalElements", orders.getTotalElements());
            map.put("totalPages", orders.getTotalPages());
            map.put("result", result);
            return new ResponseEntity(map, HttpStatus.OK);
        } catch (ParseException e) {
            e.printStackTrace();
            return new ResponseEntity("系统运行错误", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 获取订单信息
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "/orders/{orderId}")
    public ResponseEntity getOrder(@PathVariable String orderId) throws Exception {
        return (ResponseEntity) redisSyncLocker.idLock(orderId, o -> {
            Order order = orderDao.findOne(orderId);
            if (order == null) {
                return new ResponseEntity("订单不存在", HttpStatus.BAD_REQUEST);
            }
            return new ResponseEntity(orderService.orderVoCouponInstance(order), HttpStatus.OK);
        });
    }

    /**
     * 会员消费明细
     *
     * @param pageable
     * @param storeId
     * @return
     */
    @PreAuthorize("hasRole('ADMIN')")
    @RequestMapping(method = RequestMethod.GET, value = "/member-sales")
    public ResponseEntity getInventories(@PageableDefault(value = 10, sort = {"paymentTime"}, direction = Sort.Direction.DESC) Pageable pageable,
                                         @RequestParam(name = "storeId") String storeId,
                                         @RequestParam(name = "memberId") String memberId) {
        return new ResponseEntity(orderDao.findListByStoreIdAndStatusAndMemberIdAndPaymentTimeAfter(storeId,
                OrderStatus.FINISHED, memberId, DateAndTimeUtil.getMonthTime(), pageable), HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/deal/all")
    public ResponseEntity dealAllOrderStatus(@RequestBody AddMatchOrderItemParams params)throws Exception {

        makeOrderDao.updateAllOrderStatus(params.getStoreId());
        makeOrderItemDao.updateAllOrderStatus(params.getStoreId());
        return ResponseEntity.ok().body("操作成功");
    }

    /**
     * 更改订单制作状态
     *
     * @param
     * @param params
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "/update/type")
    public ResponseEntity addMatchOrderItems(@RequestBody AddMatchOrderItemParams params) {
        List<MakeOrderItem> items = makeOrderItemDao.findAllByIdIn(params.getItemIds());
        String storeId = "";
        for (MakeOrderItem item : items) {
            if (item.getMakeType().equals(OrderItemMakeType.deliveryFinished)) {
                continue;
            }
            item.setMakeType(params.getType());
            storeId = item.getStoreId();
            if (item.getMakeType().equals(OrderItemMakeType.deliveryIng)) {
                item.setMakeTime(new Date());
            }
        }
        if (params.getType().equals(OrderItemMakeType.deliveryIng)) {
            notifyMakeTypeNewOrderArrival(storeId);
        }
        if (params.getType().equals(OrderItemMakeType.deliveryFinished)) {
            notifyMakeTypeFinishNewOrderArrival(storeId);
        }
        makeOrderItemDao.save(items);
        return new ResponseEntity(items, HttpStatus.OK);
    }

    @GetMapping("lease/printing")
    public ResponseEntity leasePrinting(@RequestParam(value = "id", required = false) String id) {
        BeanPropertyRowMapper item = new BeanPropertyRowMapper<>(SalesLeaseItemDetail.class);
        item.setPrimitivesDefaultedForNullValue(true);
        Map<String, Object> map = new HashMap<>();
        List<SalesLeaseItemDetails> details = new ArrayList<>();
        WorkShift workShift = workShiftDao.findOne(id);
        List<SalesLeaseItemDetail> nowSalesItemDetails = jdbc.query("SELECT sum(get_amount) as amount,COUNT(id) as qty   ,product_name as name, product_type_name as typeName FROM lease_product_order WHERE status = 'REFUNDED'  and `store_id` =?  and `refund_time`  >=?  and `refund_time` <=? GROUP BY product_id order By amount desc "
                , item, workShift.getStoreId(), workShift.getBeginTime(), workShift.getEndTime());
        Map<String, String> stringMap = new HashMap<>();
        for (SalesLeaseItemDetail nowSalesItemDetail : nowSalesItemDetails) {
            stringMap.put(nowSalesItemDetail.getTypeName(),nowSalesItemDetail.getTypeName());

        }
        for (String s : stringMap.keySet()) {
            int total =0;
            double amount =0;
            SalesLeaseItemDetails itemDetails = new SalesLeaseItemDetails();
            for (SalesLeaseItemDetail nowSalesItemDetail : nowSalesItemDetails) {
                if (s.equals(nowSalesItemDetail.getTypeName())) {
                    SalesLeaseItemDetails.SalesLeaseItem nowItem = new SalesLeaseItemDetails.SalesLeaseItem();
                    total+=nowSalesItemDetail.getQty();
                    amount+=nowSalesItemDetail.getAmount();
                    nowItem.setName(nowSalesItemDetail.getName());
                    nowItem.setAmount(nowSalesItemDetail.getAmount());
                    nowItem.setQty(nowSalesItemDetail.getQty());
                    itemDetails.getLeaseItemList().add(nowItem);
                }
            }
            itemDetails.setTypeName(s);
            itemDetails.setAmount(amount);
            itemDetails.setQty(total);
            details.add(itemDetails);
        }
        map.put("printing", details);
        return ResponseEntity.ok(map);
    }
    /**
     * 更改订单制作状态
     *
     * @param
     * @param params
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "/boss/update/type")
    public ResponseEntity bossUpdateType(@RequestBody AddMatchOrderItemParams params) {
        MakeOrder makeOrder = makeOrderDao.findOne(params.getMakeOrderId());
        if (makeOrder == null) {
            return ResponseEntity.badRequest().body("订单异常，请刷新后重试");
        }
        List<MakeOrderItem> items = makeOrder.getItems();
        int count = 0;
        if (params.getItemIds().size() > 0) {
            items = makeOrderItemDao.findAllByIdIn(params.getItemIds());
        }
        for (MakeOrderItem item : items) {
            item.setMakeType(params.getType());

        }
        for (MakeOrderItem item : makeOrder.getItems()) {
            if (item.getMakeType().equals(OrderItemMakeType.deliveryFinished)) {
                count += 1;
            }
        }
        if (params.getType().equals(OrderItemMakeType.deliveryIng)) {
            notifyMakeTypeNewOrderArrival(makeOrder.getStoreId());
        }
        if (params.getType().equals(OrderItemMakeType.deliveryFinished)) {
            notifyMakeTypeFinishNewOrderArrival(makeOrder.getStoreId());
        }
        if (makeOrder.getItems().size() == count) {
            makeOrder.setFinished(true);
        }
        makeOrderDao.save(makeOrder);
        return new ResponseEntity(makeOrder, HttpStatus.OK);
    }

    /**
     * 获取制作中的订单
     *
     * @param
     * @param params
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "/get/by/type")
    public ResponseEntity getOrderItemByType(@RequestBody AddMatchOrderItemParams params) {
        List<OrderItemMakeType> makeTypes = new ArrayList<>();
        makeTypes.add(OrderItemMakeType.makeIng);
        makeTypes.add(OrderItemMakeType.deliveryIng);
        List<MakeOrderItem> items = makeOrderItemDao.findAllByStoreIdAndMakeTypeInOrderByAddTimeAsc(params.getStoreId(), makeTypes);
        List<MakeOrderItem> ingItem = new ArrayList<>();
        List<MakeOrderItem> deliveryItem = new ArrayList<>();
        for (MakeOrderItem item : items) {
            if (item.getMakeType().equals(OrderItemMakeType.makeIng)) {
                ingItem.add(item);
            }
            if (item.getMakeType().equals(OrderItemMakeType.deliveryIng)) {
                deliveryItem.add(item);
            }
        }
        Map map = new HashMap();
        map.put("ingItem", ingItem);
        map.put("deliveryItem", deliveryItem);
        return new ResponseEntity(map, HttpStatus.OK);
    }


    /**
     * 获取制作中的订单
     *
     * @param
     * @param params
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "/boss/get/by/type")
    public ResponseEntity getBossOrderItemByType(@RequestBody AddMatchOrderItemParams params) {
        Page<MakeOrder> items = makeOrderDao.findAllByStoreIdAndFinishedOrderByAddTimeAsc(params.getStoreId(), false, new PageRequest(params.getPage(), params.getSize()));
        return new ResponseEntity(items, HttpStatus.OK);
    }


    /**
     * 订单明细
     *
     * @param orderId
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "{orderId}/order-info")
    public ResponseEntity getOrderInfo(@PathVariable String orderId) {
        try {
            return (ResponseEntity) redisSyncLocker.idLock(orderId, o -> {
                Order order = orderDao.findOne(orderId);
                if (order == null) {
                    return new ResponseEntity("查询失败！订单信息不存在！", HttpStatus.BAD_REQUEST);
                }
                Store store = storeDao.findOne(order.getStoreId());
                OrderVo orderVo = orderService.orderVoCouponInstance(order);
                orderVo.setStoreName(store.getName());
                orderVo.setStoreAddress(store.getAddr());
                return ResponseEntity.ok(orderVo);
            });
        } catch (Exception ex) {

            log.error("getChargeRules is error=>orderId:{}", orderId, ex);
            return new ResponseEntity("系统运行错误", HttpStatus.INTERNAL_SERVER_ERROR);
        }

    }

    /**
     * 获取时间段订单信息
     *
     * @param storeId
     * @param from
     * @param to
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "{storeId}/order/list")
    public ResponseEntity getOrderList(@PathVariable String storeId,
                                       @RequestParam(name = "from") String from,
                                       @RequestParam(name = "to") String to,
                                       @RequestParam(name = "channel", defaultValue = "") PaymentChannel channel,
                                       @RequestParam(name = "source", defaultValue = "") OrderSource source,
                                       @RequestParam(name = "status", defaultValue = "") OrderStatus status,
                                       @RequestParam(name = "pageSize", defaultValue = "10") int pageSize,
                                       @RequestParam(name = "pageNumber", defaultValue = "0") int pageNumber) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            Date start = simpleDateFormat.parse(from);
            Date end = simpleDateFormat.parse(to);
            long number = orderDao.getAdminOrderVoLength(storeId, channel, source, status, start, end);
            int page = (int) Math.ceil(number / (float) pageSize);
            AdminOrderVo adminOrderVo = new AdminOrderVo(page, number);
            adminOrderVo.setOrders(orderDao.getAdminOrderVo(storeId, channel, source, status, start, end, pageNumber, pageSize));
            return ResponseEntity.ok(adminOrderVo);
        } catch (Exception ex) {
            log.error("getOrderList is error=>storeId:{},from:{},to:{}," +
                            "channel:{},source:{},status:{},pageSize:{},PageNumber:{}",
                    storeId, from, to, channel, source, status, pageSize, pageNumber, ex);
            return new ResponseEntity("系统运行错误", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /**
     * 获取时间段内商品销售信息
     *
     * @param storeId
     * @param from
     * @param to
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "{storeId}/product-sales")
    public ResponseEntity getSalesProduct(@PathVariable String storeId,
                                          @RequestParam(name = "productTypeId", defaultValue = "") String typeId,
                                          @RequestParam(name = "productId", defaultValue = "") String productId,
                                          @RequestParam(name = "from") String from,
                                          @RequestParam(name = "to") String to) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            Date start = simpleDateFormat.parse(from);
            Date end = simpleDateFormat.parse(to);
            List<String> typeIds = new ArrayList<>();
            if (StringUtils.isNotBlank(typeId) && StringUtils.isBlank(productId)) {
                typeIds = productTypeService.getTypeIds(typeId);
            }
            List<Map<String, Object>> maps = orderItemDao.getProductTotal(storeId, typeIds, productId, start, end);
            for (Map<String, Object> map : maps) {
                map.put("amount", (Math.rint(Double.parseDouble(map.get("amount").toString()) * 100)) / 100d);
            }
            return ResponseEntity.ok(maps);
        } catch (Exception ex) {
            log.error("getOrderList is error=>storeId:{},from:{},to:{}", storeId, from, to, ex);
            return new ResponseEntity("系统运行错误", HttpStatus.INTERNAL_SERVER_ERROR);

        }

    }

    private void notifyMakeTypeNewOrderArrival(String storeId) {
        try {
            Map<String, String> map = new HashMap<>();
            map.put("storeId", storeId);
            map.put("type", "DELIVERYING");
            putWs(map);
        } catch (Exception e) {
            log.warn("Fail to send websocket notify to store:{}", storeId);
        }
    }

    private void notifyMakeTypeFinishNewOrderArrival(String storeId) {
        try {
            Map<String, String> map = new HashMap<>();
            map.put("storeId", storeId);
            map.put("type", "MAKE");
            putWs(map);
        } catch (Exception e) {
            log.warn("Fail to send websocket notify to store:{}", storeId);
        }
    }

    private void putWs(Map<String, String> map) {
        try {
            //发送ws
            String url = urlUtils.getWs();
            OkHttpUtils.post(url, com.alibaba.fastjson.JSONObject.toJSONString(map));
        } catch (Exception ex) {
            log.error(" Invitation code initialization failed msg:{}", ex);
        }

    }


}